今天我們要繼續進行"錯誤"囉
我們今天要來設計錯誤的Domain type,意思是發生錯誤時,會歸類於哪一種錯誤,好像有點繞口XD
假設我們開一間餐廳,那麼會有幾種錯誤呢?
這樣做我們可以歸類這些錯誤,當我們看到這些錯誤時,就可以做特別的處理,比如說遇到食材不足,那就進貨,或是不賣那道菜,最慘就是提早打烊囉XD
package model
import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import org.springframework.http.ResponseEntity
sealed class MyError : Error() {
    @Serializable
    sealed class ValidateError : MyError()
    @Serializable
    sealed class ServerError : MyError()
    @Serializable
    data class ContainInfoError(val containInfo: String) : ValidateError()
    @Serializable
    data class DBConnectError(@Contextual val e: Error) : ServerError()
    @Serializable
    data class JsonEncodeError(@Contextual val e: Error) : ServerError()
    @Serializable
    data class CustomerNotFoundError(val customerId: String) : MyError()
    companion object {
        fun errorToResonse(myError: MyError): ResponseEntity<String> {
            return when (myError) {
                is DBConnectError ->
                    ResponseEntity.status(500).body("DB Connect Error: ${myError.e}")
                is JsonEncodeError ->
                    ResponseEntity.status(500).body("Json Encoder Error: ${myError.e}")
                is ContainInfoError ->
                    ResponseEntity.status(400).body("validation Error: ${myError.containInfo}")
                is CustomerNotFoundError ->
                    ResponseEntity.status(404).body("ID: ${myError.customerId} Not Found!")
            }
        }
    }
}
package controller
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import model.*
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
fun customerVOToCustomer(customerVO: CustomerVO) =
    when {
        customerVO.contactInfo.contains("@") -> Customer(
            Name(customerVO.name),
            Email(customerVO.contactInfo),
            Age(customerVO.age)
        )
        customerVO.contactInfo.length > 8 -> throw Error("contactInfo Too Long")
        else -> Customer(Name(customerVO.name), Phone(customerVO.contactInfo), Age(customerVO.age))
    }
@RestController
@SpringBootApplication
open class MyApplication {
    private val customerList = mutableListOf<Customer>()
    @GetMapping("/api/v1/customers")
    fun getAllCustomers(): ResponseEntity<String> {
        if (customerList.isEmpty())
            return MyError.errorToResonse(MyError.CustomerNotFoundError(customerId = "all"))
        try {
            Json.encodeToString(customerList)
        } catch (e: Error) {
            return MyError.errorToResonse(MyError.JsonEncodeError(e))
        }.let {
            return ResponseEntity.ok(it)
        }
    }
    @PostMapping("/api/v1/customers")
    fun createCustomer(@RequestBody newCustomer: String): ResponseEntity<String> {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            try {
                customerVOToCustomer(it)
            } catch (e: Error) {
                return MyError.errorToResonse(MyError.ContainInfoError(e.toString()))
            }
        }.let {
            customerList.add(it)
            it
        }.let {
            try {
                Json.encodeToString(it)
            } catch (e: Error) {
                return MyError.errorToResonse(MyError.JsonEncodeError(e))
            }
        }.let {
            return ResponseEntity.ok(it)
        }
    }
    @PutMapping("/api/v1/customers")
    fun updateCustomer(@RequestBody newCustomer: String): ResponseEntity<String> {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            customerVOToCustomer(it)
        }.let { validatedCustomer ->
            return when (val index = customerList.indexOfFirst { it.name == validatedCustomer.name }) {
                -1 -> MyError.errorToResonse(MyError.CustomerNotFoundError(customerId = index.toString()))
                else -> {
                    customerList.set(index, validatedCustomer)
                    ResponseEntity.ok("Modify success")
                }
            }
        }
    }
    @DeleteMapping("/api/v1/customers")
    fun DeleteCustomer(@RequestBody newCustomer: String): ResponseEntity<String> {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            customerVOToCustomer(it)
        }.let { validatedCustomer ->
            return when (val index = customerList.indexOfFirst { it.name == validatedCustomer.name }) {
                -1 -> MyError.errorToResonse(MyError.CustomerNotFoundError(customerId = index.toString()))
                else -> {
                    customerList.removeAt(index)
                    ResponseEntity.ok("Delete success")
                }
            }
        }
    }
}
fun main(args: Array<String>) {
    runApplication<MyApplication>(*args)
}
我們今天將錯誤處理更進一步,定義出屬於我們自己的type,這樣看到錯誤時,可以比較快地知道該怎麼處理! 別人一看到我們的程式碼,也可以很快地知道發生了甚麼事情,例如看到CustomerNotFoundError,第一眼就會想到,一定是顧客在DB中找不到了,那為甚麼找不到呢?我們就可以透過訊息來描述,比如說以這個名字來搜尋,找不到任何顧客,經過這樣的撰寫,我們的錯誤會更能表達真正的意義。